//-
//- 
//-
package com.ntf.games.framework.impl.gl;

import java.awt.Dimension;
import java.awt.event.KeyEvent;

import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLProfile;
import javax.media.opengl.awt.GLCanvas;

import com.jogamp.opengl.util.Animator;
import com.ntf.games.framework.Game;
import com.ntf.games.framework.Screen;

////////////
//- @author Me
//-
//- 
//-
public class GLGame extends Game implements Runnable
{
  // ////////////////////
  // -
  protected GLProfile       m_glprofile;
  protected GLCapabilities  m_glcapabilities;
  protected GLCanvas        m_glcanvas;
  // ////////////////////
  // -
  protected Animator        m_animator;
  // ////////////////////
  // -
  protected GLScreenManager m_screenManager;
  // ////////////////////
  // -
  protected InputHandler    m_inputHandler;
  // ////////////////////
  // -
  protected Dimension       m_size;
  // ////////////////////
  // -
  public boolean            m_bIsRunning;
  // -
  protected Thread          m_thread;
  // -
  protected Runnable        m_logicThread;

  // //////////////////////
  // - @param title
  // -
  public GLGame( String title)
  {
    super( title);
    // ////////////////////
    // -
    this.m_size = new Dimension( 640, 480);

    // ////////////////////
    // -
    this.m_glprofile = GLProfile.getDefault();
    this.m_glcapabilities = new GLCapabilities( this.m_glprofile);
    this.m_glcapabilities.setHardwareAccelerated( true);
    this.m_glcapabilities.setDoubleBuffered( true);

    // ////////////////////
    // -
    this.m_glcanvas = new GLCanvas( this.m_glcapabilities);
    this.m_glcanvas.setSize( this.m_size);
    this.m_glcanvas.setPreferredSize( this.m_size);
    this.m_glcanvas.setMinimumSize( this.m_size);
    this.m_glcanvas.setMaximumSize( this.m_size);

    // ////////////////////
    // -
    this.m_screenManager = new GLScreenManager( this.m_glcanvas);

    // ////////////////////
    // -
    // this.setInputHandler( new InputHandler());
    this.m_inputHandler = new InputHandler();
    this.m_glcanvas.addKeyListener( this.m_inputHandler);
    this.m_glcanvas.addFocusListener( this.m_inputHandler);
    this.m_glcanvas.addMouseListener( this.m_inputHandler);
    this.m_glcanvas.addMouseMotionListener( this.m_inputHandler);
    this.m_glcanvas.addMouseWheelListener( this.m_inputHandler);

    // ////////////////////
    // -
    this.m_animator = new Animator();

    // ////////////////////
    // -
    this.m_logicThread = this;

  }

  // ////////////////////
  // -
  public void setLogicThread( Runnable _runnable)
  {
    this.m_logicThread = _runnable;
  }

  // ////////////////////
  // -
  public Runnable getLogicThread( Runnable _runnable)
  {
    return(this.m_logicThread);
  }

  // ////////////////////
  // -
  public void setInputHandler( InputHandler _inputHandler)
  {
    this.m_inputHandler = _inputHandler;
    // -
    this.m_glcanvas.addKeyListener( this.m_inputHandler);
    this.m_glcanvas.addFocusListener( this.m_inputHandler);
    this.m_glcanvas.addMouseListener( this.m_inputHandler);
    this.m_glcanvas.addMouseMotionListener( this.m_inputHandler);
    this.m_glcanvas.addMouseWheelListener( this.m_inputHandler);
  }

  // ////////////////////
  // -
  public InputHandler getInputHandler()
  {
    return(this.m_inputHandler);
  }

  @Override
  public Screen getStartScreen()
  {
    // TODO Auto-generated method stub
    return null;
  }

  // //////////////////////
  // //////////////////////
  // - Thread and Animator
  // ////////////////////
  // -
  public synchronized void start()
  {
    if( !this.m_bIsRunning)
    {
      System.out.printf( "[*] [%s]: Started!\n", this.getTitle());

      // //////////////////////
      this.m_bIsRunning = true;
      // -
      this.m_thread = new Thread( this);
      this.m_thread.start();

      // //////////////////////
      this.m_animator.add( this.m_glcanvas);
      this.m_animator.start();

      // //////////////////////
      this.m_glcanvas.requestFocus();
    }
  }

  // ////////////////////
  // -
  public void stop()
  {
    System.out.printf( "[*] [%s]: Attempting to stop Threads!\n", this.getTitle());
    System.out.flush();
    if( !this.m_bIsRunning)
    {
      return;
    }
    // //////////////////////
    this.m_bIsRunning = false;

    // //////////////////////
    try
    {
      // //////////////////////
      if( Thread.currentThread() != this.m_thread)
      {
        // //////////////////////
        this.m_thread.join( 100);
        // System.out.printf( "[*] Joined!\n");
      }
      else
      {
        Thread.sleep( 100);
      }

      // //////////////////////
      if( this.m_thread.isAlive() == true)
      {
        System.out.printf( "[1] Thread failed to exit! Killing...\n");
        this.m_thread.interrupt();
      }
      // //////////////////////
      this.m_animator.stop();
      System.out.printf( "[*] [%s]: Threads Stopped!\n", this.getTitle());
      System.out.flush();

      // //////////////////////
      // this.m_glcanvas.destroy();

    }
    catch( InterruptedException e)
    {
      e.printStackTrace();
    }
  }

  // ////////////////////
  // -
  public synchronized void join()
  {
    try
    {
      this.m_thread.join();
    }
    catch( InterruptedException e)
    {
      this.m_bIsRunning = false;
      this.m_thread.interrupt();
      // e.printStackTrace();
    }

  }

  // //////////////////////
  // //////////////////////
  // - Runnable
  // //////////////////////
  // - (non-Javadoc)
  // - @see com.ntf.games.framework.Game#getStartScreen()
  // -
  // //////////////////////
  // -
  @Override
  public void run()
  {
    // //////////////////////
    // - Game Loop...
    System.out.printf( "[*] [%s] Starting Game Loop...\n", this.getTitle());
    while( this.m_bIsRunning)
    {
      // ////////////////////
      // - Test for exit...
      // ////////////////////
      if( this.m_inputHandler.m_keys[KeyEvent.VK_ESCAPE] == true)
      {
        System.out.printf( "[*] [%s] Exiting Game Loop...\n", this.getTitle());
        this.stop();
        break;
      }
      try
      {
        Thread.sleep( 100);
      }
      catch( InterruptedException e)
      {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
    System.out.printf( "[*] [%s] Game Loop Exited...\n", this.getTitle());

  }

}
